#include "matrix.h"
#include "terminal.h"
#include "console.h"
#include "thread.h"
#include "spinlock.h"

/**
 * TODO: 在单核情况下能测试的内容很有限，等到支持多核时再进行补充
 */

static mx_spinlock_rw_t spinlock1;
static mx_spinlock_rw_t spinlock2;

static mx_int32_t thread1_entry (mx_void_pt param)
{
    consoleline("thread1: spinlock1-> get rlock");
    mx_spinlock_rw_rlock(&spinlock1);
    mx_delay(0x4fffffff);
    mx_spinlock_rw_unlock(&spinlock1);
    consoleline("thread1: spinlock1-> unlocked rlock");
    mx_delay(0x4fffffff);
    consoleline("thread1: spinlock1-> get rlock");
    mx_spinlock_rw_rlock(&spinlock1);
    mx_delay(0x4fffffff);
    mx_spinlock_rw_unlock(&spinlock1);
    consoleline("thread1: spinlock1-> unlocked rlock");
    
    consoleline("thread1: spinlock1-> get wlock");
    mx_spinlock_rw_wlock(&spinlock1);
    mx_delay(0x4fffffff);
    mx_spinlock_rw_unlock(&spinlock1);
    consoleline("thread1: spinlock1-> unlocked wlock");
    mx_delay(0x4fffffff);
    consoleline("thread1: spinlock1-> get wlock");
    mx_spinlock_rw_wlock(&spinlock1);
    mx_delay(0x4fffffff);
    mx_spinlock_rw_unlock(&spinlock1);
    consoleline("thread1: spinlock1-> unlocked wlock");

    return 0;
}

static mx_int32_t thread2_entry (mx_void_pt param)
{
    consoleline("thread2: spinlock1-> get wlock");
    mx_spinlock_rw_wlock(&spinlock1);
    mx_delay(0x4fffffff);
    consoleline("thread2: spinlock2-> get rlock");
    mx_spinlock_rw_rlock(&spinlock2);
    mx_delay(0x4fffffff);
    mx_spinlock_rw_unlock(&spinlock2);
    consoleline("thread2: spinlock2-> unlocked rlock");
    mx_delay(0x4fffffff);
    mx_spinlock_rw_unlock(&spinlock1);
    consoleline("thread2: spinlock1-> unlocked rlock");
    return 0;
}

mx_size_t spinlockrwtest (mx_usize_t argc, char** argv)
{
    mx_terminal_writel("spinlockrwtest init");
    mx_spinlock_rw_init(&spinlock1);
    mx_spinlock_rw_init(&spinlock2);
    mx_thread_pt thread1 = mx_thread_register("thread1", MX_DEFAULT_PRIORITY,
                                              MX_DEFAULT_TICK, MX_DEFAULT_STACK_SIZE, thread1_entry, mx_null);
    mx_thread_start(thread1);
    mx_thread_pt thread2 = mx_thread_register("thread2", MX_DEFAULT_PRIORITY,
                                              MX_DEFAULT_TICK, MX_DEFAULT_STACK_SIZE, thread2_entry, mx_null);
    mx_thread_start(thread2);
}
MX_TERMINAL_EXPORT("spinlockrwtest", spinlockrwtest);

/**
 * spinlockrwtest init
 * thread2: spinlock1-> get wlock
 * thread2: spinlock2-> get rlock
 * thread2: spinlock2-> unlocked rlock
 * thread2: spinlock1-> unlocked rlock
 * thread1: spinlock1-> get rlock
 * thread1: spinlock1-> unlocked rlock
 * thread1: spinlock1-> get rlock
 * thread1: spinlock1-> unlocked rlock
 * thread1: spinlock1-> get wlock
 * thread1: spinlock1-> unlocked wlock
 * thread1: spinlock1-> get wlock
 * thread1: spinlock1-> unlocked wlock
 */
